using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Reflection;
using System.Text;
using System.Xml;
using Common.Utilities;
using Common.Utilities.Dispatcher;
using Workflows.Components.DALC;

namespace Workflows.Components
{
    /// <summary></summary>
    [Serializable]
    public class SubflowInstruction:InstructionBase
    {
        private List<string> _LoopableData;
        /// <summary></summary>
        public List<string> LoopableData
        {
            get { return _LoopableData; }
            set { _LoopableData = value; }
        }

        private string _IteratorDataName;
        /// <summary></summary>
        public string IteratorDataName
        {
            get { return _IteratorDataName; }
            set { _IteratorDataName = value; }
        }

        private string _IteratorDataCollectionName;
        /// <summary></summary>
        public string IteratorDataCollectionName
        {
            get { return _IteratorDataCollectionName; }
            set { _IteratorDataCollectionName = value; }
        }

        private int _CurrentInputIndex;
        /// <summary></summary>
        public int CurrentInputIndex
        {
            get { return _CurrentInputIndex; }
            set { _CurrentInputIndex = value; }
        }

        private Type _InstructionItemType;
        /// <summary></summary>
        public Type InstructionItemType
        {
            get 
            {
                return this._InstructionItemType;
            }
            set
            {
                this._InstructionItemType = value;
            }
        }

        private Guid _SubflowID;
        /// <summary></summary>
        public Guid SubFlowID
        {
            get { return _SubflowID; }
            set
            {
                _SubflowID = value;

                //if (this._SubflowID != Guid.Empty)
                //{
                //    WorkflowDesign wfDesign = WorkflowDesignDALC.GetWorkflowDesign(this._SubflowID);
                //    if (wfDesign != null && wfDesign.GlobalVariables != null && wfDesign.GlobalVariables.Length > 0)
                //    {
                //        this._SubflowGlobalVariables = new List<GlobalVariable>();
                //        this._SubflowGlobalVariables.AddRange(wfDesign.GlobalVariables);
                //    }
                //}
            }
        }
        /// <summary></summary>
        public SubflowInstruction():base(Guid.Empty,Guid.Empty)
        {
            this._SubflowID = Guid.Empty;
            this._LoopableData = null;
            this._IteratorDataName = string.Empty;
            this._IteratorDataCollectionName = string.Empty;
            this._CurrentInputIndex = -1;
            this._InstructionItemType = Type.Missing.GetType();
            //this._SubflowGlobalVariables = null;
        }
        /// <summary></summary>
        public SubflowInstruction(Guid componentID, Guid jobTicketID, 
            Guid subflowID, Type subflowInstructionType,
            List<string> loopableData, string iteratorDataName,
            string dataCollectionName, int currentIdx)
            : base(componentID, jobTicketID)
        {
            this._SubflowID = subflowID;
            this._LoopableData = loopableData;
            this._IteratorDataName = iteratorDataName;
            this._IteratorDataCollectionName = dataCollectionName;
            this._CurrentInputIndex = currentIdx;
            this._InstructionItemType = subflowInstructionType;
        }

        public override XmlNode Serialize(ref XmlDocument xDoc, ref XmlNode parentNode)
        {
            XmlNode xNode = XmlDataUtil.AddElement(ref xDoc, parentNode, "Instruction");
            XmlDataUtil.UpdateAttribute(ref xDoc, xNode, "Type", this.GetType().FullName);
            XmlDataUtil.UpdateAttribute(ref xDoc, xNode, "ComponentID", this.OwnerComponentID.ToString());
            XmlDataUtil.UpdateAttribute(ref xDoc, xNode, "WorkerID", this.OwnerWorkerInstanceID.ToString());
            XmlDataUtil.UpdateAttribute(ref xDoc, xNode, "SubmitTime", this.SubmitTime.ToString());
            XmlDataUtil.UpdateAttribute(ref xDoc, xNode, "StartTime", this.StartTime.ToString());

            XmlDataUtil.UpdateAttribute(ref xDoc,xNode,"SubflowID",this.SubFlowID.ToString());
            XmlDataUtil.UpdateAttribute(ref xDoc, xNode, "InstructionItemType", this.InstructionItemType.FullName);

            XmlDataUtil.UpdateAttribute(ref xDoc, xNode, "CurrentIndex", this.CurrentInputIndex.ToString());
            XmlDataUtil.UpdateAttribute(ref xDoc,xNode,"IteratorDataName",this.IteratorDataName);
            XmlDataUtil.UpdateAttribute(ref xDoc, xNode, "IteratorDataCollectionName",this.IteratorDataCollectionName);
            //XmlNode instructionRootNode = XmlDataUtil.AddElement(ref xDoc, xNode, "SubflowInstructionCollection");
            //if(this.InputCollection !=null && this.InputCollection.Count>0)
            //{
            //    for(int i=0;i<this.InputCollection.Count;i++)
            //    {
            //        this.InputCollection[i].Serialize(ref xDoc, ref instructionRootNode);
            //    }
            //}

            //XmlNode subflowGlobalVarRootNode = XmlDataUtil.AddElement(ref xDoc, xNode, "SubflowGlobalVariables");
            //if(this.SubflowGlobalVariables !=null && this.SubflowGlobalVariables.Count>0)
            //{
            //    foreach(GlobalVariable var in this.SubflowGlobalVariables)
            //    {
            //        XmlNode varNode = XmlDataUtil.AddElement(ref xDoc, subflowGlobalVarRootNode, "Variable");
            //        XmlDataUtil.UpdateAttribute(ref xDoc,varNode,"VariableName",var.VarName);
            //        XmlDataUtil.UpdateAttribute(ref xDoc,varNode,"DataType",((int)var.DataType).ToString());
            //        XmlDataUtil.UpdateAttribute(ref xDoc, varNode, "VariableValue", var.VarValue.ToString());
            //    }
            //}
            return xNode;
        }

        public override InstructionBase Instantiate(XmlNode xNode)
        {
            if (xNode.Attributes.GetNamedItem("Type").Value == this.GetType().FullName)
            {
                SubflowInstruction instruction = new SubflowInstruction();
                instruction.OwnerComponentID = new Guid(xNode.Attributes.GetNamedItem("ComponentID").Value);
                instruction.OwnerWorkerInstanceID = new Guid(xNode.Attributes.GetNamedItem("WorkerID").Value);
                instruction.SubmitTime = DateTime.Parse(xNode.Attributes.GetNamedItem("SubmitTime").Value);
                instruction.StartTime = DateTime.Parse(xNode.Attributes.GetNamedItem("StartTime").Value);
                instruction.InstructionItemType = Type.Missing.GetType();

                instruction.SubFlowID=new Guid(xNode.Attributes.GetNamedItem("SubflowID").Value);
                string instructItemTypeName = xNode.Attributes.GetNamedItem("InstructionItemType").Value;
                string binFolderPath = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
                DirectoryInfo dirInfo=new DirectoryInfo(binFolderPath);
                FileInfo[] dllInfos = dirInfo.GetFiles("*.dll", SearchOption.TopDirectoryOnly);
                foreach (FileInfo dllInfo in dllInfos)
                {
                    try
                    {
                        Assembly assem = Assembly.LoadFile(dllInfo.FullName);
                        Type type = assem.GetType(instructItemTypeName);
                        if(type !=null)
                        {
                            instruction.InstructionItemType = type;
                            break;
                        }
                    }
                    catch
                    {
                        Console.WriteLine("");
                    }
                }
                instruction.CurrentInputIndex = int.Parse(xNode.Attributes.GetNamedItem("CurrentIndex").Value);
                instruction.IteratorDataName = xNode.Attributes.GetNamedItem("IteratorDataName").Value;
                instruction.IteratorDataCollectionName =
                    xNode.Attributes.GetNamedItem("IteratorDataCollectionName").Value;

                //XmlNode subflowInstructionRootNode = xNode.SelectSingleNode("//SubflowInstructionCollection");
                //if(subflowInstructionRootNode !=null )
                //{
                //    instruction.CurrentInputIndex =
                //        int.Parse(subflowInstructionRootNode.Attributes.GetNamedItem("CurrentIndex").Value);
                //    instruction.InputCollection = null;
                //    if (subflowInstructionRootNode.ChildNodes != null && subflowInstructionRootNode.ChildNodes.Count > 0 && 
                //        instruction.InstructionItemType !=null && instruction.InstructionItemType != Type.Missing.GetType())
                //    {
                //        instruction.InputCollection = new List<InstructionBase>();
                //        foreach(XmlNode subflowInstructNode in subflowInstructionRootNode.ChildNodes)
                //        {
                //            InstructionBase subflowInstruction =
                //                (InstructionBase) Activator.CreateInstance(instruction.InstructionItemType);
                //            subflowInstruction = subflowInstruction.Instantiate(subflowInstructNode);
                //            instruction.InputCollection.Add(subflowInstruction);
                //        }
                //    }
                //}

                //instruction.SubflowGlobalVariables = null;
                //XmlNodeList wfVarNodes = xNode.SelectNodes("SubflowGlobalVariables/Variable");
                //if(wfVarNodes !=null && wfVarNodes.Count>0)
                //{
                //    instruction.SubflowGlobalVariables=new List<GlobalVariable>();
                //    foreach(XmlNode varNode in wfVarNodes)
                //    {
                //        GlobalVariable wfVar =new GlobalVariable();
                //        wfVar.VarName = varNode.Attributes.GetNamedItem("VariableName").Value;
                //        wfVar.DataType =
                //            (SimpleDataType) int.Parse(varNode.Attributes.GetNamedItem("DataType").Value);
                //        wfVar.VarValue = SimpleDataTypeConverter.ConvertFrom(varNode.Attributes.GetNamedItem("VariableValue").Value, wfVar.DataType).ToString();
                //        instruction.SubflowGlobalVariables.Add(wfVar);
                //    }
                //}

                return instruction;
            }
            else
            {
                throw new Exception("Unable to instantiate instruction: invalid type specified in xml node");
            }
        }

        public override Dictionary<string, Type> GetBindableMemberNames(Type[] excludeMemberFromTypes)
        {
            Dictionary<string,Type> members = base.GetBindableMemberNames(excludeMemberFromTypes);
            if(this._SubflowID !=Guid.Empty)
            {
                WorkflowDesign wfDesign = WorkflowDesignDALC.GetWorkflowDesign(this._SubflowID);
                if(wfDesign !=null && wfDesign.GlobalVariables !=null && wfDesign.GlobalVariables.Length>0)
                {
                    foreach(GlobalVariable gVar in wfDesign.GlobalVariables)
                    {
                        if(members.ContainsKey(gVar.VarName))
                        {
                            members[gVar.VarName] = SimpleDataTypeUtil.ToSystemType(gVar.DataType);
                        }
                        else
                        {
                            members.Add(gVar.VarName, SimpleDataTypeUtil.ToSystemType(gVar.DataType));
                        }
                    }
                }
            }
            return members;
        }

        public override void SetMemberValue(string memberName, object memberValue)
        {
            if (this._SubflowID != Guid.Empty)
            {
                WorkflowDesign wfDesign = WorkflowDesignDALC.GetWorkflowDesign(this._SubflowID);
                if (wfDesign != null && wfDesign.GlobalVariables != null && wfDesign.GlobalVariables.Length > 0)
                {
                    for (int i = 0; i < wfDesign.GlobalVariables.Length; i++)
                    {
                        GlobalVariable gVar = wfDesign.GlobalVariables[i];
                        if (gVar.VarName == memberName)
                        {
                            gVar.VarValue = (string) memberValue;
                            return;
                        }
                    }
                }
            }

            base.SetMemberValue(memberName, memberValue);
        }
    }
}
